/*
 * Copyright 2015 The Netty Project
 *
 * The Netty Project licenses this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */
package io.netty.util;

/**
 * Abstraction for hash code generation and equality comparison.
 */
public interface HashingStrategy<T> {

  /**
   * Generate a hash code for {@code obj}.
   * <p>
   * This method must obey the same relationship that {@link java.lang.Object#hashCode()} has with
   * {@link java.lang.Object#equals(Object)}:
   * <ul>
   * <li>Calling this method multiple times with the same {@code obj} should return the same
   * result</li>
   * <li>If {@link #equals(Object, Object)} with parameters {@code a} and {@code b} returns {@code
   * true} then the return value for this method for parameters {@code a} and {@code b} must return
   * the same result</li>
   * <li>If {@link #equals(Object, Object)} with parameters {@code a} and {@code b} returns {@code
   * false} then the return value for this method for parameters {@code a} and {@code b} does
   * <strong>not</strong> have to return different results results. However this property is
   * desirable.</li>
   * <li>if {@code obj} is {@code null} then this method return {@code 0}</li>
   * </ul>
   */
  int hashCode(T obj);

  /**
   * Returns {@code true} if the arguments are equal to each other and {@code false} otherwise. This
   * method has the following restrictions:
   * <ul>
   * <li><i>reflexive</i> - {@code equals(a, a)} should return true</li>
   * <li><i>symmetric</i> - {@code equals(a, b)} returns {@code true} if {@code equals(b, a)}
   * returns {@code true}</li>
   * <li><i>transitive</i> - if {@code equals(a, b)} returns {@code true} and {@code equals(a, c)}
   * returns {@code true} then {@code equals(b, c)} should also return {@code true}</li>
   * <li><i>consistent</i> - {@code equals(a, b)} should return the same result when called
   * multiple
   * times assuming {@code a} and {@code b} remain unchanged relative to the comparison
   * criteria</li>
   * <li>if {@code a} and {@code b} are both {@code null} then this method returns {@code
   * true}</li>
   * <li>if {@code a} is {@code null} and {@code b} is non-{@code null}, or {@code a} is non-{@code
   * null} and {@code b} is {@code null} then this method returns {@code false}</li>
   * </ul>
   */
  boolean equals(T a, T b);

  /**
   * A {@link HashingStrategy} which delegates to java's {@link Object#hashCode()} and {@link
   * Object#equals(Object)}.
   */
  @SuppressWarnings("rawtypes")
  HashingStrategy JAVA_HASHER = new HashingStrategy() {
    @Override
    public int hashCode(Object obj) {
      return obj != null ? obj.hashCode() : 0;
    }

    @Override
    public boolean equals(Object a, Object b) {
      return (a == b) || (a != null && a.equals(b));
    }
  };
}
